#include <stdio.h>
#include <stdlib.h>
#include "tortuga.h"

static const int CANTIDAD_OPERACIONES = 6;
void inicializarTortuga(tTortuga *tortuga) {
	tColor blanco, negro, rojo, verde, azul;
	pintarPixel(&blanco, 255, 255, 255);
	pintarPixel(&negro, 0, 0, 0);
	pintarPixel(&rojo, 255, 0, 0);
	pintarPixel(&verde, 0, 255, 0);
	pintarPixel(&azul, 0, 0, 255);
	pintarPixel(&negro, 0, 0, 0);
	tortuga->posicion.x = 0;
	tortuga->posicion.y = 0;
	tortuga->angulo = 0;
	tortuga->color = negro;
	tortuga->pluma = 1;
	tortuga->colores[0] = blanco;
	tortuga->colores[1] = negro;
	tortuga->colores[2] = rojo;
	tortuga->colores[3] = verde;
	tortuga->colores[4] = azul;
	tortuga->bm = (tBitmap *) malloc(sizeof(tBitmap));
	inicializarData(tortuga->bm);
	inicializarOperaciones(tortuga->operaciones);
}

/* Inicializa el vector de punteros a operaciones, creando una operacion
 * por cada una de las que puede realizar la tortuga. */
void inicializarOperaciones(tOperacion *operaciones[]) {
	tOperacion *fAdelante = (tOperacion *) malloc(sizeof(tOperacion));
	tOperacion *fIzquierda = (tOperacion *) malloc(sizeof(tOperacion));
	tOperacion *fDerecha = (tOperacion *) malloc(sizeof(tOperacion));
	tOperacion *fConPluma = (tOperacion *) malloc(sizeof(tOperacion));
	tOperacion *fSinPluma = (tOperacion *) malloc(sizeof(tOperacion));
	tOperacion *fColor = (tOperacion *) malloc(sizeof(tOperacion));
	fAdelante->funcion = adelante;
	fAdelante->nombre = 'a';
	fIzquierda->funcion = izquierda;
	fIzquierda->nombre = 'i';
	fDerecha->funcion = derecha;
	fDerecha->nombre = 'd';
	fConPluma->funcion = conPluma;
	fConPluma->nombre = 'c';
	fSinPluma->funcion = sinPluma;
	fSinPluma->nombre = 's';
	fColor->funcion = color;
	fColor->nombre = 'f';
	operaciones[0] = fAdelante;
	operaciones[1] = fIzquierda;
	operaciones[2] = fDerecha;
	operaciones[3] = fConPluma;
	operaciones[4] = fSinPluma;
	operaciones[5] = fColor;
}

void calcular_xy(int x0, int y0, int angle, int d, int *x1, int *y1) {
#define R(x) (((x) >= 0) ? ((int)((x)+0.5)) : ((int)((x)-0.5)))
*x1 = R(((double)x0) + ((double)d) * cos((((double)angle)*M_PI)/180));
*y1 = R(((double)y0) + ((double)d) * sin((((double)angle)*M_PI)/180));
}

void adelante(tTortuga *tortuga, int pasos) {
	int x1 = 0, y1 = 0;
	tPunto posicionActual = {0, 0}, posicionFinal = {0, 0};
	posicionActual.x = tortuga->posicion.x/PASOS_POR_PIXEL;
	posicionActual.y = tortuga->posicion.y/PASOS_POR_PIXEL;
	calcular_xy(tortuga->posicion.x, tortuga->posicion.y, 
				tortuga->angulo, pasos, &x1, &y1);
	posicionFinal.x = x1/PASOS_POR_PIXEL;
	posicionFinal.y = y1/PASOS_POR_PIXEL;
	if (tortuga->pluma)
		dibujarLinea(posicionActual, posicionFinal, tortuga->bm, tortuga->color);
	tortuga->posicion.x = x1;
	tortuga->posicion.y = y1;
}

void derecha(tTortuga *tortuga, int angulo) {
	int aux = tortuga->angulo += angulo;
	tortuga->angulo = aux % 360;
}

void izquierda(tTortuga *tortuga, int angulo) {
	derecha(tortuga, 360 - angulo);
}

void color(tTortuga *tortuga, int numero) {
	tortuga->color = tortuga->colores[numero];
}

void conPluma(tTortuga *tortuga, int valor) {
	tortuga->pluma = 1;
}

void sinPluma(tTortuga *tortuga, int valor) {
	tortuga->pluma = 0;
}

/* Realiza una operacion determinada en base a una instruccion. */
void ejecutarInstruccion(tTortuga *tortuga, tInstruccion *instruccion) {
	for (int i = 0; i < CANTIDAD_OPERACIONES; i++)
		if(tortuga->operaciones[i]->nombre == instruccion->identificador) {
			(tortuga->operaciones[i]->funcion)(tortuga, instruccion->valor);
			break;
		}
}

void borrarOperaciones(tOperacion *operaciones[]) {
	for(int i = 0;i < CANTIDAD_OPERACIONES;i++)
		free(operaciones[i]);
}

void liberarMatrizTortuga(tBitmap *bm) {
	free(bm);
}
